import random
import copy
import matplotlib.pyplot as plt
import matplotlib
font = {'family': 'SimHei'}
matplotlib.rc('font', **font)
# 考虑参数:入场人数、折扣、营业额、利润
class Client:
    # 个人模型
    def __init__(self, fund):
        # 每个账户拥有一定初始资金、20%优惠券票数
        self.fund = fund    # 资金
        self.discount_num = 0   # 优惠券额度，初始为0
        self.product_ls = []    # 个人已买入未卖出的产品

    # 零售场
    def buy1(self, shop, product):
        price, num, discount1, discount2, limit = shop.product_dic[product]
        if num == 0:
            del shop.product_dic[product]
            return '该产品已售完'
        if self.fund < price:
            print('账户余额不足',self.fund , price * discount1)
            return False
        else:
            self.fund -= price * discount1              # 减少资金
            shop.product_dic[product][1] -= 1      # 减少产品数量
            self.discount_num += price * 0.2            # 增加1张优惠券
            self.product_ls.append(product)
            return True

    # 批发场
    def buy2(self, shop, product):
        price, num, discount1, discount2, limit = shop.product_dic[product]
        if num == 0:
            del shop.product_dic[product]
            return '该产品已售完'
        if self.fund < price * discount2:
            print('账户余额不足',self.fund ,price * discount2)
            return False
        if self.discount_num:
            money = price * discount2
            if limit <= self.discount_num:    # 仅当优惠券面额大于当前购买的产品优惠券限额时可以购买
                self.fund -= money      # 减少资金
                shop.product_dic[product][1] -= 1  # 减少产品数量
                self.discount_num -= limit
                self.product_ls.append(product)
                return True
            else:
                print('优惠券额度不够，无法购买')
                return False
        else:
            print('没有优惠券，无法进入批发场购买')
            return False

    # 寄售场(与零售场相同，仅仅是身份的对调，此时要考虑平台抽成20%，变为购买者的优惠券了)
    def sell(self, data):
        if self.product_ls:
            while self.product_ls:
                product = self.product_ls.pop()     # 取出产品
                price, num, discount1, discount2, limit = data[product]
                self.fund += price * 0.79       # 20%抽成+1%手续费
            return True
        else:
            print('当前没有产品可寄售')
            return True

class Shop:
    # 产品模型
    def __init__(self, data):
        self.product_dic = data    # 产品列表


def loop(data, people, fund):
    # 先把客户实例存好，再循环调用
    client = [Client(fund[i]) for i in range(people)]
    for t in range(10):     # 循环10个周期
        shop = Shop(copy.deepcopy(data))   # 每次新周期将商品填充好
        li1 = []
        # n1 = random.randint(1, people)   # 随机有n1个人进零售场
        n1 = people
        # 零售场开启
        r_person = []   # 参加过零售场的人记录进来
        count = 0
        while count < n1:
            # c = random.choice(client)
            c = client[count]
            if not c in r_person:   # 保证不是重复的人
                r_person.append(c)
                count += 1
            else:
                continue
            # for i in range(random.randint(1, 3)):   # 每人随机买1~3件产品
            for i in range(3):
                try:
                    res = c.buy1(shop, sorted(shop.product_dic.items(), key=lambda item: item[1][0])[0][0])
                    if res == '该产品已售完':
                        c.buy1(shop, sorted(shop.product_dic.items(), key=lambda item: item[1][0])[0][0])
                except IndexError:  # 产品卖完了
                    pass
            print(shop.product_dic)
        # 批发场开启
        # n2 = random.randint(1, n1)  # 随机有n2个人进批发场，至多n1个人
        n2 = n1
        b_person = []   # 记录参加批发场的人，避免重复选取
        count = 0
        while count < n2:
            # c = random.choice(r_person)
            c = r_person[count]
            if not c in b_person:
                b_person.append(c)
                count += 1
            else:
                continue
            li2 = list(shop.product_dic.values())
            if not li2:     # 产品卖完，后面的人没得买了
                break
            li_price = list(map(lambda x: x[0],li2))
            li_discount_money = list(map(lambda x: x[-1],li2))
            min_price, min_discount_money = min(li_price), min(li_discount_money)
            while c.discount_num >= min_discount_money and c.fund >= min_price:  # 此时每个人尽量将优惠券/资金用完
                try:
                    res = c.buy2(shop, sorted(shop.product_dic.items(), key=lambda item: item[1][0])[0][0])
                    if res == '该产品已售完':
                        res = c.buy2(shop, sorted(shop.product_dic.items(), key=lambda item: item[1][0])[0][0])
                    if not res:
                        break
                except IndexError:  # 产品卖完了
                    break
        # 一次性全卖
        for c in r_person:  # 至少参加过零售场的才可寄售
            c.sell(data)
        for k, c in enumerate(client):
            li1.append((k, c.fund-fund[k]))
        ls.append(li1)
        print(shop.product_dic)
    return ls

def func1(data, people, fund):
    # 先把客户实例存好，再循环调用
    client = [Client(fund[i]) for i in range(people)]
    for t in range(10):  # 循环10个周期
        shop = Shop(copy.deepcopy(data))  # 每次新周期将商品填充好

if __name__ == '__main__':
    data = {
        # 零售价,数量,零售场折扣,批发场折扣,优惠券限额
        '手机A': [1000, 100, 0.1, 0.05, 200],
        '手机B': [1500, 100, 0.2, 0.1, 300],
        '手机C': [2000, 80, 0.3, 0.15, 400],
        '手机D': [2500, 60, 0.4, 0.25, 500],
        '手机E': [3000, 50, 0.5, 0.3, 600],
        '手机F': [4000, 40, 0.6, 0.35, 700],
        '手机G': [5000, 30, 0.7, 0.5, 800],
        '手机H': [6000, 20, 0.8, 0.6, 900],
        '手机I': [7000, 10, 0.9, 0.7, 1000],
    }
    people = 1000
    fund_ls = [10000 for _ in range(people)]
    ls = []
    loop(data, people, fund_ls)
    for i in range(10):
        choose_ls = list(map(lambda x: x[i][-1], ls))
        print(choose_ls)
        plt.xlabel('周期数')
        plt.ylabel('已提现的利润')
        plt.plot(choose_ls)
    plt.show()
    # print(sum(map(lambda x: x.values(), data)))